package nickthissen.iracing.networking;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.concurrent.TimeoutException;

import nickthissen.iracing.common.Constants;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.params.HttpClientParams;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.json.JSONObject;

import android.content.Context;
import android.net.http.AndroidHttpClient;
import android.util.Log;
import android.widget.Toast;

public abstract class NetworkMethod
{
	public final static int GET = 1;
	public final static int POST = 2;
	public final static int SERVICE = 1;
	public final static int FORUM = 2;
	
	//private static CookieStore cookieStore;
	
	public final static String USER_AGENT = "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506; .NET CLR 3.5.21022)";
	public final static String ACCEPT = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-ms-application, application/vnd.ms-xpsdocument, application/xaml+xml, application/x-ms-xbap, application/x-shockwave-flash, */*";

    private final static int TIMEOUT = 50000; //ms

    protected int method;
    protected int source;
	protected String url;
	
	public NetworkMethod(int method, int source, String url)
	{
		this.method = method;
		this.source = source;
		this.url = this.createUrl(url);
	}
	
	protected String createUrl(String relativeOrAbsoluteUrl)
	{
		if (relativeOrAbsoluteUrl.startsWith("/")) {
			return getBaseUrl() + relativeOrAbsoluteUrl;
		}
		return relativeOrAbsoluteUrl;
	}
	
	protected abstract String getBaseUrl();

    private static BasicCookieStore cookieStore;
    public static BasicCookieStore getCookieStore()
    {
        if (cookieStore == null) cookieStore = new BasicCookieStore();

        return cookieStore;
    }
    public static void setCookieStore(BasicCookieStore cookies)
    {
        cookieStore = cookies;
    }

    public static void resetCookieStore()
    {
        cookieStore = null;
    }

//    //private static AsyncHttpClient client;
//    public static AsyncHttpClient getClient()
//    {
//        //if (client == null) client = new AsyncHttpClient();
//        AsyncHttpClient client = new AsyncHttpClient();
//        client.getHttpClient().getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
//        return client;
//    }
	
	public HttpResult execute(Context context) throws Exception
	{
		return execute(context, null);
	}
	
	public HttpResult execute(Context context, Params param) throws Exception
	{
		return sendRequest(context, url, param, method);
	}

//    private String sendRequest(Context context, String url, Params param, int method) throws Exception
//    {
//        Log.i("AsyncClient", "Start getting client.");
//        AsyncHttpClient client = getClient();
//        Log.i("AsyncClient", "Finished getting client.");
//
//        Log.i("AsyncClient", "Start getting cookiestore.");
//        client.setCookieStore(getCookieStore());
//        Log.i("AsyncClient", "Finished getting cookiestore.");
//        client.setTimeout(TIMEOUT);
//        client.setUserAgent(USER_AGENT);
//
//        AwaitResponseHandler handler = new AwaitResponseHandler();
//        boolean completed;
//        if (method == NetworkMethod.GET)
//        {
//            RequestParams p = new RequestParams();
//            if (param != null) p = param.toRequestParams();
//
//            Log.i("AsyncClient", "Start GET. " + url);
//            client.get(url, p, handler);
//            completed = handler.latch.await(TIMEOUT, TimeUnit.MILLISECONDS);
//            Log.i("AsyncClient", "Finished GET." + url);
//        }
//        else
//        {
//            HttpEntity entity = null;
//            if (param != null) entity = new StringEntity(param.toJson().toString(), "utf-8");
//
//            Log.i("AsyncClient", "Start POST." + url);
//            client.post(context, url, entity, "application/json", handler);
//            completed = handler.latch.await(TIMEOUT, TimeUnit.MILLISECONDS);
//            Log.i("AsyncClient", "Finished POST." + url);
//        }
//
//        if (completed)
//        {
//            return handler.result;
//        }
//        else
//        {
//            throw new TimeoutException();
//        }
//    }
//
//    private class AwaitResponseHandler extends AsyncHttpResponseHandler
//    {
//        public CountDownLatch latch;
//        public String result;
//
//        public AwaitResponseHandler()
//        {
//            this.latch = new CountDownLatch(1);
//        }
//
//        @Override
//        public void onSuccess(String s)
//        {
//            Log.i("Request result", s);
//            this.result = s;
//            this.latch.countDown();
//            super.onSuccess(s);
//        }
//
//        @Override
//        public void onFailure(Throwable throwable, String s)
//        {
//            Log.e("Request result", "Failed: " + throwable.getMessage() + "\nString: " + s);
//            this.latch.countDown();
//            super.onFailure(throwable, s);
//        }
//    }

	private HttpResult sendRequest(Context context, String url, Params param, int method)
	{
		try
		{
            AndroidHttpClient httpClient = AndroidHttpClient.newInstance(USER_AGENT);

            // Define parameters
		    HttpParams httpParams = httpClient.getParams();
		    HttpConnectionParams.setConnectionTimeout(httpParams, TIMEOUT);
		    HttpConnectionParams.setSoTimeout(httpParams, TIMEOUT);
            HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1);
            HttpClientParams.setRedirecting(httpParams, true);

			// Create HTTP request object (get/post)
			HttpRequestBase http;
			HttpContext localContext = new BasicHttpContext();

			if (method == POST)
			{
				// Create HTTP POST and set parameters
				http = new HttpPost(url);
				if (param != null)
				{
					JSONObject json = param.toJson();
				    HttpEntity bodyEntity = new StringEntity(json.toString(), "utf8");
				    ((HttpPost)http).setEntity(bodyEntity);
				}
			}
			else
			{
				if (param != null)
				{
					// Set parameters in URL and create HTTP GET
					url = param.appendToUrl(url);
				}
				http = new HttpGet(url);
			}

			http.addHeader("Accept", ACCEPT);

			if (this.source == SERVICE)
			{
			    http.addHeader("Content-Type", "application/json; charset=utf-8");
			}
			else if (this.source == FORUM)
			{
                http.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");

				// Attach cookiestore
				localContext.setAttribute(ClientContext.COOKIE_STORE, getCookieStore());
			}


		    // Get a response
            HttpResult result = new HttpResult();

            HttpResponse response;
            try
            {
                response = httpClient.execute(http, localContext);
            }
            catch (ConnectTimeoutException ex)
            {
                throw new TimeoutException();
            }
			HttpEntity entity = response.getEntity();


            // Don't want to log the user's password
            String safeUrl = url;
            if (url.startsWith(Networking.LOGIN_URL)) {
                safeUrl = "<forum login URL>";
            }

            result.Status = response.getStatusLine();
            String status = "Status: " + result.Status.getStatusCode() + " - " + result.Status.getReasonPhrase();
            Log.i(Constants.TAG, "(URL: " + safeUrl + ") Status: " + status);
            /// DEBUG!!!!!!!!
            if (result.Status.getStatusCode() != 200)
            {
                Toast.makeText(context, "Status: " + status, Toast.LENGTH_LONG).show();
            }

			if (entity != null)
			{
			    InputStream instream = entity.getContent();
			    BufferedReader reader = new BufferedReader(new InputStreamReader(instream));
			    StringBuilder sb = new StringBuilder();

			    String line = null;
			    while ((line = reader.readLine()) != null)
			        sb.append(line + "\n");

			    result.Contents = sb.toString();
			    instream.close();
			}

			http.abort();
            httpClient.close();


            Log.i(Constants.TAG, "(URL: " + safeUrl + ") Result: " + result.Contents);

			return result;
		}
		catch (Exception ex)
		{
			Log.e(Constants.TAG, "Error during web request:\n" + ex.toString());
			return null;
		}
	}

}
